package my.mall.front.api.service

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
import com.baomidou.mybatisplus.core.metadata.IPage
import com.baomidou.mybatisplus.extension.plugins.pagination.Page
import my.mall.common.bean.JsonParser
import my.mall.common.pojo.CommonResp
import my.mall.common.pojo.PageParam
import my.mall.common.pojo.PageResp
import my.mall.common.util.BigDecimalUtils.fenToYuan
import my.mall.common.util.FutureUtils.waitAllTasks
import my.mall.common.util.RespUtils.success
import my.mall.db.entity.Goods
import my.mall.db.entity.GoodsExt
import my.mall.db.entity.GoodsSku
import my.mall.db.mapper.GoodsExtMapper
import my.mall.db.mapper.GoodsMapper
import my.mall.db.mapper.GoodsSkuMapper
import my.mall.front.api.pojo.goods.GoodsDetail
import my.mall.front.api.pojo.goods.GoodsItem
import my.mall.front.api.pojo.goods.SkuDetail
import my.mall.front.api.pojo.goods.detail.AttrInfo
import my.mall.front.api.pojo.goods.detail.SkuInfo
import my.mall.front.api.pojo.goods.detail.SpecInfo
import my.mall.front.api.util.MoneyUtils
import my.mall.front.api.util.SpecUtils
import org.springframework.stereotype.Service
import org.springframework.util.StringUtils
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ThreadPoolExecutor

@Service
class GoodsService(
    private val executor: ThreadPoolExecutor,
    private val jsonParser: JsonParser,
    private val goodsMapper: GoodsMapper,
    private val goodsExtMapper: GoodsExtMapper,
    private val goodsSkuMapper: GoodsSkuMapper
) {

    fun getGoodsList(param: PageParam): CommonResp<PageResp<GoodsItem>> {
        var page: IPage<Goods> = Page(param.pageNum, param.pageSize)
        page = goodsMapper.selectPage(
            page, QueryWrapper<Goods>()
                .select(
                    Goods.ID,
                    Goods.GOODS_PRICE,
                    Goods.GOODS_NAME,
                    Goods.SELLING_POINT,
                    Goods.MAIN_IMG_URL,
                )
                .eq(Goods.GOODS_STATUS, 1)
                .orderByAsc(Goods.GOODS_ORDER)
                .orderByDesc(Goods.ID)
        )
        val resList: MutableList<GoodsItem> = ArrayList(page.records.size)
        for (goods in page.records) {
            val item = GoodsItem()
            item.id = goods.id
            item.goodsPrice = MoneyUtils.convertFenToYuan(goods.goodsPrice!!)
            item.goodsName = goods.goodsName
            item.sellingPoint = goods.sellingPoint
            item.mainImgUrl = goods.mainImgUrl
            resList.add(item)
        }
        return success(page.current, page.size, page.total, resList)
    }

    fun getGoodsDetail(goodsId: Long?): GoodsDetail {
        val goodsDetail = GoodsDetail()
        val goodsFuture = CompletableFuture.runAsync({
            val goods = goodsMapper.selectOne(
                QueryWrapper<Goods>()
                    .select(
                        Goods.GOODS_NAME,
                        Goods.SELLING_POINT,
                        Goods.GOODS_PRICE,
                    )
                    .eq(Goods.ID, goodsId)
            )
            if (goods != null) {
                goodsDetail.id = goodsId
                goodsDetail.goodsName = goods.goodsName
                goodsDetail.sellingPoint = goods.sellingPoint
                goodsDetail.goodsPrice = MoneyUtils.convertFenToYuan(goods.goodsPrice!!)
            }
        }, executor)
        val goodsExtFuture = CompletableFuture.runAsync({
            val goodsExt = goodsExtMapper.selectOne(
                QueryWrapper<GoodsExt>()
                    .select(
                        GoodsExt.MAIN_IMG_URLS,
                        GoodsExt.CONTENT_IMG_URLS,
                        GoodsExt.ATTR_DETAIL,
                    )
                    .eq(GoodsExt.GOODS_ID, goodsId)
            )
            if (goodsExt != null) {
                if (StringUtils.hasLength(goodsExt.mainImgUrls)) {
                    goodsDetail.mainImgUrls = jsonParser.parseJsonToList(goodsExt.mainImgUrls, String::class.java)
                }
                if (StringUtils.hasLength(goodsExt.contentImgUrls)) {
                    goodsDetail.contentImgUrls = jsonParser.parseJsonToList(goodsExt.contentImgUrls, String::class.java)
                } else {
                    goodsDetail.contentImgUrls = goodsDetail.mainImgUrls
                }
                if (StringUtils.hasLength(goodsExt.attrDetail)) {
                    goodsDetail.attrList = jsonParser.parseJsonToList(goodsExt.attrDetail, AttrInfo::class.java)
                }
            }
        }, executor)
        val skuListFuture = CompletableFuture.runAsync({
            val goodsSkuList = goodsSkuMapper.selectList(
                QueryWrapper<GoodsSku>()
                    .select(
                        GoodsSku.ID,
                        GoodsSku.STOCK_NUM,
                        GoodsSku.SKU_PRICE,
                        GoodsSku.SPEC_IDS,
                        GoodsSku.SPEC_DETAIL,
                        GoodsSku.SKU_IMG_URL,
                    )
                    .eq(GoodsSku.GOODS_ID, goodsId)
            )
            val specMap: MutableMap<String, SpecInfo> = HashMap()
            val skuInfoList: MutableList<SkuInfo> = ArrayList(goodsSkuList.size)
            for (sku in goodsSkuList) {
                val specDetail = sku.specDetail
                val attrList = jsonParser.parseJsonToJsonNode(specDetail)
                for (attr in attrList) {
                    val attrName = attr["attrName"].asText()
                    var specInfo = specMap[attrName]
                    if (specInfo == null) {
                        specInfo = SpecInfo(attrName, mutableListOf())
                        specMap[attrName] = specInfo
                    }
                    val itemId = attr["itemId"].asLong()
                    val itemName = attr["itemName"].asText()
                    val specItem = SpecInfo.SpecItem(itemId, itemName)
                    if (!specInfo.attrValueList.contains(specItem)) {
                        specInfo.attrValueList.add(specItem)
                    }
                }
                val skuInfo = SkuInfo()
                skuInfo.id = sku.id
                skuInfo.stockNum = sku.stockNum!!
                skuInfo.skuPrice = fenToYuan(sku.skuPrice)
                skuInfo.specIds = sku.specIds!!
                skuInfo.specDetail = sku.specDetail
                skuInfo.skuImgUrl = sku.skuImgUrl
                skuInfoList.add(skuInfo)
            }
            goodsDetail.skuList = skuInfoList
            goodsDetail.specList = ArrayList(specMap.values)
        }, executor)
        waitAllTasks(goodsFuture, goodsExtFuture, skuListFuture)
        return goodsDetail
    }

    fun getSkuDetail(goodsId: Long?, skuId: Long?): SkuDetail {
        val detail = SkuDetail()
        val goodsFuture = CompletableFuture.runAsync {
            val goods = goodsMapper.selectOne(
                QueryWrapper<Goods>()
                    .select(
                        Goods.GOODS_NAME,
                        Goods.MAIN_IMG_URL,
                    )
                    .eq(Goods.ID, goodsId)
            )
            detail.goodsName = goods.goodsName
            detail.mainImgUrl = goods.mainImgUrl
        }
        val skuFuture = CompletableFuture.runAsync {
            val sku = goodsSkuMapper.selectOne(
                QueryWrapper<GoodsSku>()
                    .select(
                        GoodsSku.ID,
                        GoodsSku.GOODS_ID,
                        GoodsSku.SKU_PRICE,
                        GoodsSku.SKU_IMG_URL,
                        GoodsSku.SPEC_DETAIL,
                    )
                    .eq(GoodsSku.ID, skuId)
            )
            detail.skuId = sku.id
            detail.goodsId = sku.goodsId
            detail.skuPrice = sku.skuPrice
            detail.skuImgUrl = sku.skuImgUrl
            val specDetail = sku.specDetail
            if (!StringUtils.hasLength(specDetail)) {
                return@runAsync
            }
            detail.skuSpec = SpecUtils.parseSpec(jsonParser, specDetail)
        }
        waitAllTasks(goodsFuture, skuFuture)
        return detail
    }
}
